package com.favccxx.message.domain.message.processor.entity;

import com.favccxx.message.domain.message.entity.process.MapRule;
import com.favccxx.message.domain.message.entity.process.MessageProcessRule;
import com.favccxx.message.domain.message.processor.MessageProcessor;
import com.favccxx.message.domain.message.processor.ProcessEntity;
import com.favccxx.message.infrastructure.util.jackson.JacksonUtil;
import com.jayway.jsonpath.JsonPath;
import com.jayway.jsonpath.PathNotFoundException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.*;

@Slf4j
@Component("EntityMessageProcessor")
public class EntityMessageProcessor implements MessageProcessor<String, String> {

    @Override
    public String process(String data, Object... params) {
        if (StringUtils.isBlank(data)) {
            log.info("Empty data");
            return "";
        }

        String processRule = (String) params[0];
        try {
            MessageProcessRule messageProcessRule = JacksonUtil.jsonToObject(processRule, MessageProcessRule.class);
            String entityName = messageProcessRule.getName();
            List<MapRule> ruleList = messageProcessRule.getRules();

            List<Map<String, Object>> dataListMap = convertData(data, ruleList);

            ProcessEntity processEntity = new ProcessEntity();
            processEntity.setName(entityName);
            processEntity.setDataMap(dataListMap);

            String processData = JacksonUtil.toJsonString(processEntity);
            log.info("---------->" + processData);

            return processData;

        } catch (IOException e) {
            log.error("!!!!! Deal message failed, invalid message process rules. ", e.getMessage());
            return null;
        }
    }

    private List<Map<String, Object>> convertData(String data, List<MapRule> ruleList) {
        List<Map<String, Object>> dataListMap = new ArrayList<>();

        Set<String> arraySet = getArrayKeyAndMaxLength(ruleList);
        if (arraySet.isEmpty()) {
            dataListMap = convertSimpleData(data, ruleList);
            return dataListMap;
        }

        // Only one array, don't need a * b
        if (arraySet.size() == 1) {
            dataListMap = convertSingleArrayData(data, ruleList, arraySet.stream().findFirst().get());
            return dataListMap;
        }

        // Deal array json data

        return dataListMap;
    }

    /**
     * 不含数组的JSON结构转换
     *
     * @param data
     * @param ruleList
     */
    private List<Map<String, Object>> convertSimpleData(String data, List<MapRule> ruleList) {
        List<Map<String, Object>> dataListMap = new ArrayList<>();
        Map<String, Object> dataMap = new HashMap<>();
        ruleList.forEach(mapRule -> {
            Object value = JsonPath.read(data, mapRule.getSourceExpression());
            if (value == null) {
                value = mapRule.getTargetDefaultValue();
            }

            //TODO: changeValueType(); do it later
            dataMap.put(mapRule.getTargetName(), value);
        });

        dataListMap.add(dataMap);
        return dataListMap;
    }

    /**
     * 处理只有一种数据情形的数据
     *
     * @param data
     * @param ruleList
     * @return
     */
    private List<Map<String, Object>> convertSingleArrayData(String data, List<MapRule> ruleList, String arrayKey) {
        List<Map<String, Object>> dataListMap = new ArrayList<>();

        List<Map<String, Object>> list = JsonPath.read(data, arrayKey);

        for (int i = 0, l = list.size(); i < l; i++) {
            Map<String, Object> map = new HashMap<>();

            for (MapRule mapRule : ruleList) {
                String expression = mapRule.getSourceExpression();
                String preExpression = expression.substring(0, expression.lastIndexOf("."));

                Object value = null;
                if (preExpression.endsWith(".*")) {
                    StringBuffer arrayExpressionSb = new StringBuffer();
                    arrayExpressionSb.append(preExpression.substring(0, preExpression.length() - 2))
                            .append("[").append(i).append("]")
                            .append(expression.substring(expression.lastIndexOf(".")));
                    //String arrayExpression = preExpression.substring(0, preExpression.length()-2) + "[" + i + "]." + expression.substring(expression.lastIndexOf("."));
                    String path = arrayExpressionSb.toString();
                    try {
                        value = JsonPath.read(data, path);
                    } catch (PathNotFoundException e) {
                        log.info("Current node not exist data." + path);
                    }

                } else {
                    try {
                        value = JsonPath.read(data, mapRule.getSourceExpression());
                    } catch (PathNotFoundException e) {
                        log.info("Current node not exist data." + mapRule.getSourceExpression());
                    }
                }

                if (value == null) {
                    map.put(mapRule.getTargetName(), mapRule.getTargetDefaultValue());
                } else {
                    map.put(mapRule.getTargetName(), value);
                }

                //TODO: changeValueType(); do it later

            }


            dataListMap.add(map);
        }

        return dataListMap;
    }


    /**
     * 获取映射集合的数组 key 列表
     *
     * @param ruleList
     * @return
     */
    private Set<String> getArrayKeyAndMaxLength(List<MapRule> ruleList) {
        Set<String> expressionSet = new HashSet<>();
        ruleList.forEach(mapRule -> {
            String expression = mapRule.getSourceExpression();
            if (expression.indexOf("*") > 0) {
                String arrayKey = expression.substring(0, expression.lastIndexOf("."));
                expressionSet.add(arrayKey);
            }

        });

        return expressionSet;
    }


}
